local addon = AceLibrary("AceAddon-2.0"):new("AceDB-2.0", "AceEvent-2.0")

local function debug_OnAttributeChanged_hook(frame, name, value)
	local s = string.format("%s %s %s", frame:GetName(), tostring(name) or "nil", tostring(value) or "nil")
	ChatFrame3:AddMessage(s)
end

function addon:AddDebugFrame(parent, name)
	local t = parent:CreateTexture(nil, "OVERLAY")
	t:SetAllPoints(parent)
	t:SetTexture(0.3, 0.95, 0.3, 0.5)
	t:Show()
	parent.debugTexture = t
	
	local s = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	s:SetAllPoints(parent)
	s:SetText(name)
	s:SetJustifyH("CENTER")
	s:SetJustifyV("MIDDLE")
	parent.debugString = s
	parent:HookScript("OnAttributeChanged", debug_OnAttributeChanged_hook)
end

function addon:CreateHeader(parent, anchor)
	local f = CreateFrame("Frame", "TrackingHeader", parent, "SecureStateHeaderTemplate")

	f:SetAllPoints(anchor or parent)
	f:SetFrameStrata("DIALOG")
	f:Show()
	
	self:AddDebugFrame(f, "HEADER")
	return f
end

function addon:CreateAnchor()
	local f = CreateFrame("Button", "TrackingAnchor", UIParent, "SecureAnchorEnterTemplate")

--~ 	f:SetAttribute("hidestates", "0")
--~ 	f:SetAttribute("ofsx", 0)
--~ 	f:SetAttribute("ofsy", 0)

	f:SetAttribute("childstate", 2)
	f:SetAttribute("*childraise-OnEnter", true)
	f:SetAttribute("*childstate-OnEnter", "enter")
	f:SetAttribute("*childstate-OnLeave", "leave")
	
	f:SetWidth(32)
	f:SetHeight(32)
	f:SetPoint("CENTER", 100, 0)
	f:Show()
		
	self:AddDebugFrame(f, "ANCHOR")
	
	return f
end

function addon:InitializeAnchoring(anchor, header)
	header:SetAttribute("addchild", anchor)
	anchor:SetAttribute("anchorchild", header)
	anchor:SetAttribute("*childraise-OnEnter", true)
	anchor:SetAttribute("*childstate-OnEnter", "enter")
	anchor:SetAttribute("*childstate-OnLeave", "leave")
	
	local delay = 2 -- self.db.profile.delay
	if delay == 0 then
		header:SetAttribute("statemap-anchor-enter", "1:2")
		header:SetAttribute("statemap-anchor-leave", "2:1")
	else
		header:SetAttribute("statemap-anchor-enter", "1:2")
		header:SetAttribute("statemap-anchor-leave", ";")
		header:SetAttribute("delaystatemap-anchor-leave", "2:1")
		header:SetAttribute("delaytimemap-anchor-leave", "2:"..delay)
		header:SetAttribute("delayhovermap-anchor-leave", "2:true")
	end
	header:SetAttribute("state", "1")
end

local BUTTON_WIDTH = 256
local BUTTON_HEIGHT = 24
local TABLET_OFFSET = 5

function addon:CreateTablet()
	local f = CreateFrame("Frame", "TrackingTablet", UIParent)
	f:SetBackdrop({
		bgFile = "Interface\\TutorialFrame\\TutorialFrameBackground",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = true,
		edgeSize = 16,
		tileSize = 32,
		insets = {
			left = 5,
			right = 5,
			top = 5,
			bottom = 5
		}
	})
	f:SetWidth(BUTTON_WIDTH + 2 * TABLET_OFFSET)
	f:SetHeight(BUTTON_HEIGHT + 2 * TABLET_OFFSET)
	f:SetPoint("CENTER", 0, 100)
	
	self:AddDebugFrame(f, "TABLET")
	return f
end

function addon:CreateButton(index)
	local f = CreateFrame("Button", "TrackingButton"..index, self.tablet, "SecureActionButtonTemplate");
	f:SetFrameStrata("DIALOG")
	f.texture = f:CreateTexture(nil, "BACKGROUND")
	f.texture:SetWidth(BUTTON_HEIGHT)
	f.texture:SetHeight(BUTTON_HEIGHT)
	f.texture:SetPoint("LEFT")
	f.text = f:CreateFontString(nil, "ARTWORK", "GameFontNormal")
	f.text:SetWidth(BUTTON_WIDTH - BUTTON_HEIGHT - TABLET_OFFSET)
	f.texture:SetHeight(BUTTON_HEIGHT)
	f.text:SetPoint("LEFT", f.texture, "RIGHT", TABLET_OFFSET, 0)
	f:SetWidth(BUTTON_WIDTH)
	f:SetHeight(BUTTON_HEIGHT)
	self:AddDebugFrame(f, "B"..index)
	return f
end

function addon:GetButton(name, icon)
	local f
	do
		local buttons = self.buttons
		local index = buttons.index
		local pool = buttons.pool
		f = pool[index]
		if not f then
			f = self:CreateButton(index)
			pool[index] = f
		end
		buttons.index = index + 1
	end
	
	f.icon = icon
	f.texture:SetTexture(icon)
	f.text:SetText(name)
	
	f:SetAttribute("type", "spell")
	f:SetAttribute("spell", name)
	
	return f
end

do
	local BS = AceLibrary("Babble-Spell-2.2")
	local race = select(2, UnitRace("player"))
	local class = select(2, UnitClass("player"))
	local BOOKTYPE_SPELL = BOOKTYPE_SPELL
	local insert = table.insert
	
	local abilities = {
		[BS["Find Herbs"]] = true,
		[BS["Find Minerals"]] = true,
	}
	local tabs = {
		[1] = true,
	}
	
	if race == "DWARF" then
		abilities[BS["Find Treasure"]] = true
	end
	if class == "HUNTER" then
		abilities[BS["Track Beasts"]] = true
		abilities[BS["Track Demons"]] = true
		abilities[BS["Track Dragonkin"]] = true
		abilities[BS["Track Elementals"]] = true
		abilities[BS["Track Giants"]] = true
		abilities[BS["Track Hidden"]] = true
		abilities[BS["Track Humanoids"]] = true
		abilities[BS["Track Undead"]] = true
		tabs[4] = true
	elseif class == "PALADIN" then
		abilities[BS["Sense Undead"]] = true
		tabs[2] = true
	elseif class == "WARLOCK" then
		abilities[BS["Sense Demons"]] = true
		tabs[3] = true
	elseif class == "DRUID" then
		abilities[BS["Track Humanoids"]] = 3
		tabs[3] = true
	end
	
	local sorts = {}

	function addon:FillTablet()
		local tablet = self.tablet
		self.buttons.index = 1
		
		local index = 1
		for tab in pairs(tabs) do
			local offset, count = select(3, GetSpellTabInfo(tab))
			for spell = offset + 1, offset + count do
				local name = GetSpellName(spell, BOOKTYPE_SPELL)
				local v = abilities[name]
				if type(v) == "number" and select(3, GetShapeshiftFormInfo(v)) or v == true then
					local t = sorts[index]
					if not t then
						t = {}
						sorts[index] = t
					end
					t.name = name
					t.icon = GetSpellTexture(spell, BOOKTYPE_SPELL)
					t.valid = true
					index = index + 1
				end
			end
		end
		for i = index, #sorts do
			sorts[i].valid = nil
		end
		table.sort(sorts, 
			function (v1, v2) 
				if v1.valid == v2.valid then
					return v1.name < v2.name
				else
					return v1.valid 
				end
			end)
		local anchor
		for _, ability in ipairs(sorts) do
			if not ability.valid then break end
			local f = self:GetButton(ability.name, ability.icon)
			if anchor then
				f:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT")
			else
				f:SetPoint("TOPLEFT", self.tablet, TABLET_OFFSET, -TABLET_OFFSET)
			end
			f:Show()
			anchor = f
		end
		for i = self.buttons.index, #self.buttons.pool do
			self.buttons.pool[i]:Hide()
		end
		self.tablet:SetHeight((self.buttons.index - 1) * BUTTON_HEIGHT + 2 * TABLET_OFFSET)
	end
end

function addon:OnInitialize()
	local base = CreateFrame("Frame", nil, UIParent)
	base:SetWidth(64)
	base:SetHeight(64)
	base:SetPoint("CENTER")
	
	local header = self:CreateHeader(base)
	local anchor = self:CreateAnchor()
	
	self:InitializeAnchoring(anchor, header)
	
	local tablet = self:CreateTablet()
	header:SetAttribute("addchild", tablet)
	tablet:SetAttribute("showstates", "2")
	
	self.base = base
	self.header = header
	self.anchor = anchor
	self.tablet = tablet
	self.buttons = {
		pool = {},
		index = 1,
	}
	
	self:FillTablet()
end
